/*******************************************************************************
* Copyright (c) 2010 The Eclipse Foundation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* The Eclipse Foundation - initial API and implementation
*******************************************************************************/
package org.eclipse.epp.mpc.tests.service;
import static org.hamcrest.Matchers.*;
import static org.junit.Assume.*;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.security.cert.Certificate;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Platform;
import org.eclipse.epp.internal.mpc.core.MarketplaceClientCore;
import org.eclipse.epp.internal.mpc.core.MarketplaceClientCorePlugin;
import org.eclipse.epp.internal.mpc.core.ServiceLocator;
import org.eclipse.epp.internal.mpc.core.service.DefaultMarketplaceService;
import org.eclipse.epp.mpc.core.model.IIu;
import org.eclipse.epp.mpc.core.model.IIus;
import org.eclipse.epp.mpc.core.model.INode;
import org.eclipse.epp.mpc.core.model.ISearchResult;
import org.eclipse.epp.mpc.core.service.IMarketplaceUnmarshaller;
import org.eclipse.epp.mpc.core.service.QueryHelper;
import org.eclipse.epp.mpc.core.service.UnmarshalException;
import org.eclipse.epp.mpc.tests.Categories.RemoteTests;
import org.eclipse.epp.mpc.tests.LoggingSuite;
import org.eclipse.equinox.internal.p2.core.helpers.ServiceHelper;
import org.eclipse.equinox.internal.p2.repository.Activator;
import org.eclipse.equinox.p2.core.IProvisioningAgent;
import org.eclipse.equinox.p2.core.UIServices;
import org.hamcrest.Matcher;
import org.hamcrest.MatcherAssert;
import org.junit.Assert;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.ComparisonFailure;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.rules.ExternalResource;
import org.junit.rules.TestRule;
import org.junit.rules.TestWatcher;
import org.junit.runner.Description;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;
import org.junit.runners.model.Statement;
import org.osgi.framework.ServiceRegistration;
@RunWith(Parameterized.class)
@Category(RemoteTests.class)
@Ignore("Disabled until test data on marketplace-staging.eclipse.org can be recreated")
public class SolutionCompatibilityFilterTest {
private static final String BASE_URL = "http://marketplace-staging.eclipse.org";
public static enum System {
WIN32(Platform.OS_WIN32, Platform.WS_WIN32), //
LINUX(Platform.OS_LINUX, Platform.WS_GTK), //
MACOS(Platform.OS_MACOSX, Platform.WS_COCOA);
private final String os;
private final String ws;
private System(String os, String ws) {
this.os = os;
this.ws = ws;
}
public void applyTo(Map<String, String> metaParams) {
metaParams.put(DefaultMarketplaceService.META_PARAM_OS, os);
metaParams.put(DefaultMarketplaceService.META_PARAM_WS, ws);
}
}
private static final String JAVA_PRODUCT_ID = "epp.package.java";
private static final String SDK_PRODUCT_ID = "org.eclipse.sdk.ide";
public static enum EclipseRelease {
UNKNOWN(null, null, null, null), //
INDIGO(JAVA_PRODUCT_ID, "1.4.2.20120131-1457", "3.7.0.v20110110", null), //
JUNO_3_8(SDK_PRODUCT_ID, "3.8.0.v201206081200", "3.8.0.v20120521-2346", null), //
JUNO_3_8_WITH_PLATFORM(SDK_PRODUCT_ID, JUNO_3_8.productVersion(), JUNO_3_8.runtimeVersion(),
"3.8.0.v201206081200"), //
JUNO(JAVA_PRODUCT_ID, "1.5.0.20120131-1544", "3.8.0.v20120521-2346", null), //
JUNO_WITH_PLATFORM(JAVA_PRODUCT_ID, JUNO.productVersion(), JUNO.runtimeVersion(), "4.2.0.v201206081400"), //
JUNO_SR2(JAVA_PRODUCT_ID, "1.5.2.20130110-1126", "3.8.0.v20120521-2346", "4.2.2.v201302041200"), //
KEPLER(JAVA_PRODUCT_ID, "2.0.0.20130613-0530", "3.9.0.v20130326-1255", "4.3.0.v20130605-2000"), //
KEPLER_SR2(JAVA_PRODUCT_ID, "2.0.2.20140224-0000", "3.9.100.v20131218-1515", "4.3.2.v20140221-1700"), //
LUNA(JAVA_PRODUCT_ID, "4.4.0.20140612-0500", "3.10.0.v20140318-2214", "4.4.0.v20140606-1215"), //
LUNA_SR2(JAVA_PRODUCT_ID, "4.4.2.20150219-0708", "3.10.0.v20140318-2214", "4.4.2.v20150204-1700"), //
MARS(JAVA_PRODUCT_ID, "4.5.0.20150326-0704", "3.10.0.v20150112-1422", "4.5.0.v20150203-1300");
private final String productId;
private final String productVersion;
private final String runtimeVersion;
private final String platformVersion;
private EclipseRelease(String productId, String productVersion, String runtimeVersion, String platformVersion) {
this.productId = productId;
this.productVersion = productVersion;
this.runtimeVersion = runtimeVersion;
this.platformVersion = platformVersion;
}
private EclipseRelease(String productVersion, String runtimeVersion, String platformVersion) {
this(JAVA_PRODUCT_ID, productVersion, runtimeVersion, platformVersion);
}
public String productId() {
return productId;
}
public String productVersion() {
return productVersion;
}
public String runtimeVersion() {
return runtimeVersion;
}
public String platformVersion() {
return platformVersion;
}
public void applyTo(Map<String, String> metaParams) {
if (productVersion == null) {
metaParams.remove(DefaultMarketplaceService.META_PARAM_PRODUCT);
metaParams.remove(DefaultMarketplaceService.META_PARAM_PRODUCT_VERSION);
} else {
metaParams.put(DefaultMarketplaceService.META_PARAM_PRODUCT, productId);
metaParams.put(DefaultMarketplaceService.META_PARAM_PRODUCT_VERSION, productVersion);
}
if (runtimeVersion == null) {
metaParams.remove(DefaultMarketplaceService.META_PARAM_RUNTIME_VERSION);
} else {
metaParams.put(DefaultMarketplaceService.META_PARAM_RUNTIME_VERSION, runtimeVersion);
}
if (platformVersion == null) {
metaParams.remove(DefaultMarketplaceService.META_PARAM_PLATFORM_VERSION);
} else {
metaParams.put(DefaultMarketplaceService.META_PARAM_PLATFORM_VERSION, platformVersion);
}
}
public static EclipseRelease previous(EclipseRelease release) {
if (release == UNKNOWN) {
return null;
}
int previousOrdinal = release.ordinal() - 1;
return previousOrdinal > UNKNOWN.ordinal() ? values()[previousOrdinal] : null;
}
public static EclipseRelease next(EclipseRelease release) {
if (release == UNKNOWN) {
return null;
}
int nextOrdinal = release.ordinal() + 1;
return values().length > nextOrdinal ? values()[nextOrdinal] : null;
}
}
public static enum Solution {
JUNO("test-entry-juno", EclipseRelease.JUNO_3_8, EclipseRelease.JUNO_SR2), //
KEPLER("test-entry-kepler", EclipseRelease.KEPLER, EclipseRelease.KEPLER_SR2), //
LUNA("test-entry-luna", EclipseRelease.LUNA, EclipseRelease.LUNA_SR2), //
MARS("test-entry-mars", EclipseRelease.MARS, EclipseRelease.MARS), //
JUNO_AND_EARLIER("test-entry-juno-and-earlier", null, EclipseRelease.JUNO_SR2), //
KEPLER_AND_EARLIER("test-entry-kepler-and-earlier", null, EclipseRelease.KEPLER_SR2), //
KEPLER_LUNA("test-entry-kepler-luna", EclipseRelease.KEPLER, EclipseRelease.LUNA_SR2), //
KEPLER_MARS("test-entry-kepler-luna-mars", EclipseRelease.KEPLER, EclipseRelease.MARS), //
LUNA_WIN32("test-entry-luna-win32", EclipseRelease.LUNA, EclipseRelease.LUNA_SR2, System.WIN32), //
LUNA_LINUX_MACOS("test-entry-luna-mac-linux", EclipseRelease.LUNA, EclipseRelease.LUNA_SR2, System.LINUX,
System.MACOS), //
MULTI_VERSION("test-entry-multi-version", null, EclipseRelease.MARS), //
PSEUDO_CONFLICT("test-entry-pseudo-conflict", EclipseRelease.KEPLER, EclipseRelease.MARS), //
CONFLICT("test-entry-conflict", EclipseRelease.KEPLER, EclipseRelease.MARS), //
UNINSTALLABLE(""/* TODO */, null, null, System.WIN32, System.MACOS, System.LINUX);
private final String id;
private final String shortName;
private final EclipseRelease minRelease;
private final EclipseRelease maxRelease;
private final System[] systems;
private Solution(String shortName, EclipseRelease minRelease, EclipseRelease maxRelease, System... systems) {
this.id = null;
this.shortName = shortName;
this.minRelease = minRelease;
this.maxRelease = maxRelease;
this.systems = systems;
}
public String id() {
return id;
}
public String shortName() {
return shortName;
}
public String url() {
return BASE_URL + "/content/" + shortName;
}
public String query() {
return shortName;
}
public boolean installable() {
//TODO
return true;
}
public EclipseRelease minRelease() {
return minRelease;
}
public EclipseRelease maxRelease() {
return maxRelease;
}
public System[] systems() {
return systems == null || systems.length == 0 ? System.values() : systems;
}
public boolean isCompatible(System system) {
if (systems == null || system == null) {
return true;
}
for (System aSystem : systems()) {
if (aSystem == system) {
return true;
}
}
return false;
}
public boolean isCompatible(EclipseRelease release) {
if (release == EclipseRelease.UNKNOWN) {
return true;
}
if (minRelease() != null) {
if (minRelease().ordinal() > release.ordinal()) {
return false;
}
}
if (maxRelease() != null) {
if (maxRelease().ordinal() < release.ordinal()) {
return false;
}
}
return true;
}
}
@Parameters(name = "{index}__{0}__with__{1}_{2}")
public static Iterable<Object[]> data() {
List<Object[]> data = new ArrayList<Object[]>();
checkSolutionReleaseBounds(data, Solution.JUNO);
checkSolutionReleaseBounds(data, Solution.KEPLER);
checkSolutionReleaseBounds(data, Solution.LUNA);
checkSolutionReleaseBounds(data, Solution.MARS);
//bug 466627
checkSolutionWithEclipse(data, "Solution should not be installable in an older release", Solution.MARS,
EclipseRelease.INDIGO, null);
checkSolutionWithEclipse(data, "Solution should not be installable in an older release", Solution.MARS,
EclipseRelease.JUNO_3_8, null);
checkSolutionWithEclipse(data, "Solution should not be installable in an older release", Solution.MARS,
EclipseRelease.JUNO, null);
checkSolutionReleaseBounds(data, Solution.JUNO_AND_EARLIER);
checkSolutionReleaseBounds(data, Solution.KEPLER_AND_EARLIER);
checkSolutionReleaseBounds(data, Solution.KEPLER_LUNA);
checkSolutionData(data, "Solution should have version 1.0.0 features for Kepler release", Solution.KEPLER_LUNA,
EclipseRelease.KEPLER, System.WIN32, "1.0.0", "http://example.org/kepler", "org.example.feature.kepler");
checkSolutionData(data, "Solution should have version 1.1.0 features for Luna release", Solution.KEPLER_LUNA,
EclipseRelease.LUNA, System.WIN32, "1.1.0", "http://example.org/luna", "org.example.feature.luna");
checkSolutionReleaseBounds(data, Solution.KEPLER_MARS);
checkSolutionData(data, "Solution should have version 1.0.0 features for Kepler release", Solution.KEPLER_MARS,
EclipseRelease.KEPLER, System.WIN32, "1.0.0", "http://example.org/kepler-luna",
"org.example.feature.kepler.luna");
checkSolutionData(data, "Solution should have version 1.0.0 features for Luna release", Solution.KEPLER_MARS,
EclipseRelease.LUNA, System.WIN32, "1.0.0", "http://example.org/kepler-luna",
"org.example.feature.kepler.luna");
checkSolutionData(data, "Solution should have version 1.1.0 features for Mars release", Solution.KEPLER_MARS,
EclipseRelease.MARS, System.WIN32, "1.1.0", "http://example.org/mars", "org.example.feature.mars");
checkSolutionWithEclipse(data, "Solution should be installable in a compatible release and os",
Solution.LUNA_WIN32, EclipseRelease.LUNA, System.WIN32);
checkSolutionWithEclipse(data, "Solution should not be installable in an incompatible os", Solution.LUNA_WIN32,
EclipseRelease.LUNA, System.LINUX);
checkSolutionWithEclipse(data, "Solution should not be installable in an older release", Solution.LUNA_WIN32,
EclipseRelease.KEPLER, System.WIN32);
checkSolutionWithEclipse(data, "Solution should not be installable in an older release and incompatible os",
Solution.LUNA_WIN32, EclipseRelease.KEPLER, System.LINUX);
checkSolutionWithEclipse(data, "Solution should not be installable in a newer release", Solution.LUNA_WIN32,
EclipseRelease.MARS, System.WIN32);
checkSolutionWithEclipse(data, "Solution should not be installable in a newer release and incompatible os",
Solution.LUNA_WIN32, EclipseRelease.MARS, System.LINUX);
checkSolutionWithEclipse(data, "Solution should be installable in a compatible release and os",
Solution.LUNA_LINUX_MACOS, EclipseRelease.LUNA, System.LINUX);
checkSolutionWithEclipse(data, "Solution should be installable in a compatible release and os",
Solution.LUNA_LINUX_MACOS, EclipseRelease.LUNA, System.MACOS);
checkSolutionWithEclipse(data, "Solution should not installable in an incompatible os",
Solution.LUNA_LINUX_MACOS, EclipseRelease.LUNA, System.WIN32);
checkSolutionData(data, "Solution should have version 1.1.0 features for Juno release", Solution.MULTI_VERSION,
EclipseRelease.JUNO, System.LINUX, "1.1.0", "http://example.org/juno-kepler",
"org.example.feature.juno.kepler");
checkSolutionData(data, "Solution should have version 1.1.0 features for Kepler release",
Solution.MULTI_VERSION, EclipseRelease.KEPLER, System.MACOS, "1.1.0", "http://example.org/juno-kepler",
"org.example.feature.juno.kepler");
checkSolutionData(data, "Solution should have version 1.1.1 features for Kepler release on Windows",
Solution.MULTI_VERSION, EclipseRelease.KEPLER, System.WIN32, "1.1.1",
"http://example.org/juno-kepler-win32", "org.example.feature.juno.kepler.win32");
checkSolutionData(data, "Solution should have version 1.2.0 features for Luna release", Solution.MULTI_VERSION,
EclipseRelease.LUNA, System.WIN32, "1.2.0", "http://example.org/luna",
"org.example.feature.luna.nolinux");
checkSolutionWithEclipse(data, "Solution should be incompatible with Linux for Luna release",
Solution.MULTI_VERSION, EclipseRelease.LUNA, System.LINUX, false);
checkSolutionData(data, "Solution should have version 1.3.0 features for Mars release", Solution.MULTI_VERSION,
EclipseRelease.MARS, System.MACOS, "1.3.0", "http://example.org/mars",
"org.example.feature.mars.nolinux");
checkSolutionWithEclipse(data, "Solution should be incompatible with Linux for Mars release",
Solution.MULTI_VERSION, EclipseRelease.MARS, System.LINUX, false);
checkSolutionData(
data,
"Solution with overlapping versions but separate os (pseudo-conflict) should have version 1.0.0 for Luna on Mac",
Solution.PSEUDO_CONFLICT, EclipseRelease.LUNA, System.MACOS, "1.0.0", "http://example.org/maclinux",
"org.example.feature.maclinux");
checkSolutionData(
data,
"Solution with overlapping versions but separate os (pseudo-conflict) should have version 1.1.0 for Luna on Windows",
Solution.PSEUDO_CONFLICT, EclipseRelease.LUNA, System.WIN32, "1.1.0", "http://example.org/win",
"org.example.feature.win");
checkSolutionData(
data,
"Solution with overlapping versions (real conflict) should have correct version for non-overlapping release (older version)",
Solution.CONFLICT, EclipseRelease.KEPLER, System.WIN32, "1.0.0", "http://example.org/kepler-luna",
"org.example.feature.keplerluna");
checkSolutionData(
data,
"Solution with overlapping versions (real conflict) should have latest version for overlapping release",
Solution.CONFLICT, EclipseRelease.LUNA, System.WIN32, "1.1.0", "http://example.org/luna-mars",
"org.example.feature.lunamars");
checkSolutionData(
data,
"Solution with overlapping versions (real conflict) should have latest version for overlapping release",
Solution.CONFLICT, EclipseRelease.LUNA, System.MACOS, "1.1.0", "http://example.org/luna-mars",
"org.example.feature.lunamars");
checkSolutionData(
data,
"Solution with overlapping versions (real conflict) should have correct version for non-overlapping release (newer version)",
Solution.CONFLICT, EclipseRelease.MARS, System.WIN32, "1.1.0", "http://example.org/luna-mars",
"org.example.feature.lunamars");
// checkSolutionWithEclipse(data, Solution.UNINSTALLABLE, EclipseRelease.UNKNOWN, System.WIN32);
// checkSolutionWithEclipse(data, Solution.UNINSTALLABLE, EclipseRelease.UNKNOWN, System.LINUX);
// checkSolutionWithEclipse(data, Solution.UNINSTALLABLE, EclipseRelease.UNKNOWN, System.MACOS);
return data;
}
private static void checkSolutionData(List<Object[]> data, String testDescription, Solution solution,
EclipseRelease release, System system, String version, String site, String... features) {
if (release == null) {
release = EclipseRelease.UNKNOWN;
}
if (system == null) {
system = System.WIN32;
}
boolean releaseCompatible = solution.isCompatible(release);
boolean systemCompatible = solution.isCompatible(system);
boolean compatible = releaseCompatible && systemCompatible;
checkSolutionData(data, testDescription, solution, release, system, compatible, version, site, features);
}
private static void checkSolutionData(List<Object[]> data, String testDescription, Solution solution,
EclipseRelease release, System system, boolean compatible, String version, String site, String... features) {
if (release == null) {
release = EclipseRelease.UNKNOWN;
}
if (system == null) {
system = System.WIN32;
}
if (features != null && features.length == 0) {
features = null;
}
for (Object[] objects : data) {
if (objects[0] == solution && objects[1] == release && objects[2] == system) {
if (((version == null && objects[3] == null) || (version != null && version.equals(objects[3])))
&& ((site == null && objects[4] == null) || (site != null && site.equals(objects[4])))) {
if (features == null && objects[5] == null) {
return;
}
Set<String> allFeatures = new HashSet<String>(Arrays.asList(features));
Set<String> allDataFeatures = new HashSet<String>(Arrays.asList((String[]) objects[5]));
if (allFeatures.equals(allDataFeatures)) {
return;
}
}
}
}
data.add(new Object[] { solution, release, system, version, site, features, compatible, testDescription });
}
private static void checkSolutionReleaseBounds(List<Object[]> data, Solution solution) {
EclipseRelease minRelease = solution.minRelease();
EclipseRelease maxRelease = solution.maxRelease();
EclipseRelease beforeMin = minRelease == null ? null : EclipseRelease.previous(minRelease);
EclipseRelease afterMax = maxRelease == null ? null : EclipseRelease.next(maxRelease);
if (beforeMin != null) {
checkSolutionWithEclipse(data, "Solution should not be installable in an older release", solution,
beforeMin, null);
}
for (EclipseRelease release : EclipseRelease.values()) {
if (solution.isCompatible(release)) {
checkSolutionWithEclipse(data, "Solution should be installable in a compatible release", solution,
release, null);
}
}
checkSolutionWithEclipse(data, "Solution should be installable in an unknown release", solution,
EclipseRelease.UNKNOWN, null);
if (afterMax != null) {
checkSolutionWithEclipse(data, "Solution should not be installable in a newer release", solution, afterMax,
null);
}
}
private static void checkSolutionWithEclipse(List<Object[]> data, String testDescription, Solution solution,
EclipseRelease release, System system) {
checkSolutionData(data, testDescription, solution, release, system, null, null);
}
private static void checkSolutionWithEclipse(List<Object[]> data, String testDescription, Solution solution,
EclipseRelease release, System system, boolean compatible) {
checkSolutionData(data, testDescription, solution, release, system, compatible, null, null);
}
private static void assertTrue(String message, boolean b, Object... details) {
Assert.assertTrue(format(message, flatten(b, details)), b);
}
private static void assertNotNull(Object value) {
Assert.assertNotNull(value);
}
private static void assertEquals(String message, Object o1, Object o2, Object... details) {
Assert.assertEquals(format(message, flatten(o1, o2, details)), o1, o2);
}
private static void assertNotNull(String message, Object value, Object... details) {
Assert.assertNotNull(format(message, flatten(value, details)), value);
}
private static <T> void assertThat(String reason, T actual, Matcher<? super T> matcher, Object... details) {
MatcherAssert.assertThat(format(reason, flatten(actual, details)), actual, matcher);
}
private static void assertNull(String message, Object value, Object... details) {
Assert.assertNull(format(message, flatten(value, details)), value);
}
private static String format(String message, Object... details) {
if (details == null || details.length == 0) {
return message;
}
String contentPrefix = BASE_URL + "/content/";
for (int i = 0; i < details.length; i++) {
Object detail = details[i];
if (detail instanceof INode) {
INode node = (INode) detail;
String url = node.getUrl();
if (url != null) {
if (url.startsWith(contentPrefix)) {
String shortName = url.substring(contentPrefix.length());
detail = shortName;
} else {
detail = url;
}
} else {
detail = node.getId();
}
} else if (detail instanceof Solution) {
Solution solution = (Solution) detail;
detail = solution.shortName();
}
details[i] = detail;
}
return MessageFormat.format(message, details);
}
private static Object[] flatten(Object... values) {
List<Object> flattened = new ArrayList<Object>();
for (Object object : values) {
flatten(flattened, object);
}
return flattened.toArray(new Object[flattened.size()]);
}
private static void flatten(List<Object> flattened, Object value) {
if (value instanceof Object[]) {
Object[] child = (Object[]) value;
for (Object object : child) {
flatten(flattened, object);
}
} else {
flattened.add(value);
}
}
@ClassRule
public static TestRule stageCredentialsRule = new ExternalResource() {
private UIServices originalService;
private UIServices credentialsService;
@Override
protected void before() throws Throwable {
IProvisioningAgent agent = (IProvisioningAgent) ServiceHelper.getService(Activator.getContext(),
IProvisioningAgent.SERVICE_NAME);
UIServices adminUIService = (UIServices) agent.getService(UIServices.SERVICE_NAME);
originalService = adminUIService;
credentialsService = new UIServices() {
@Override
public AuthenticationInfo getUsernamePassword(String location, AuthenticationInfo previousInfo) {
if (previousInfo == null) {
return getUsernamePassword(location);
}
return null;
}
@Override
public AuthenticationInfo getUsernamePassword(String location) {
if (location != null && location.contains("marketplace-staging")) {
return new AuthenticationInfo("testuser", "plaintext", false);
}
throw new AssertionError("Unexpectedly required authentication for host " + location);
}
@Override
public TrustInfo getTrustInfo(Certificate[][] untrustedChain, String[] unsignedDetail) {
throw new AssertionError("Unexpectedly required trustinfo");
}
};
agent.registerService(UIServices.SERVICE_NAME, credentialsService);
}
@Override
protected void after() {
UIServices originalService = this.originalService;
UIServices credentialsService = this.credentialsService;
this.originalService = null;
this.credentialsService = null;
IProvisioningAgent agent = (IProvisioningAgent) ServiceHelper.getService(Activator.getContext(),
IProvisioningAgent.SERVICE_NAME);
Object currentUIService = agent.getService(UIServices.SERVICE_NAME);
if (currentUIService == credentialsService && originalService != null) {
agent.registerService(UIServices.SERVICE_NAME, originalService);
}
}
};
@Rule
public final TestRule xmlDumpRule = new TestWatcher() {
private ServiceRegistration<IMarketplaceUnmarshaller> unmarshallerRegistration;
@Override
protected void starting(final Description description) {
final IMarketplaceUnmarshaller marketplaceUnmarshaller = org.eclipse.epp.mpc.core.service.ServiceHelper
.getMarketplaceUnmarshaller();
unmarshallerRegistration = MarketplaceClientCorePlugin.getDefault().getServiceHelper()
.registerMarketplaceUnmarshaller(new IMarketplaceUnmarshaller() {
public <T> T unmarshal(InputStream in, Class<T> type, IProgressMonitor monitor)
throws UnmarshalException, IOException {
byte[] input = capture(in);
in = null;
try {
return marketplaceUnmarshaller
.unmarshal(new ByteArrayInputStream(input), type, monitor);
} catch (UnmarshalException ex) {
dump(description, ex, input);
throw ex;
} catch (IOException ex) {
dump(description, ex, input);
throw ex;
} catch (RuntimeException ex) {
dump(description, ex, input);
throw ex;
}
}
private byte[] capture(InputStream in) throws IOException {
try {
ByteArrayOutputStream dump = new ByteArrayOutputStream(32768);
byte[] buffer = new byte[8192];
for (int read = -1; (read = in.read(buffer)) != -1;) {
dump.write(buffer, 0, read);
}
byte[] input = dump.toByteArray();
return input;
} finally {
in.close();
}
}
});
}
@Override
protected void finished(Description description) {
if (unmarshallerRegistration != null) {
unmarshallerRegistration.unregister();
}
}
void dump(Description description, Throwable ex, byte[] input) {
String fileName = description.getDisplayName() + "_"
+ new SimpleDateFormat("yyyyMMdd-HHmmss").format(new Date());
fileName = safeFileName(fileName);
File outputDir = findOutputDir();
File dumpFile = new File(outputDir, fileName + "-response.dump");
for (int i = 1; dumpFile.exists(); i++) {
dumpFile = new File(outputDir, fileName + "_" + i + "-response.dump");
}
failed(new AssertionError("Dumping XML stream to " + dumpFile.getAbsolutePath()), description);
FileOutputStream os = null;
try {
os = new FileOutputStream(dumpFile);
os.write(input);
} catch (Exception e) {
failed(e, description);
} finally {
if (os != null) {
try {
os.close();
} catch (IOException e) {
failed(e, description);
}
}
}
}
private File findOutputDir() {
File targetDir = new File("target");
if (targetDir.isDirectory()) {
File sureFireDir = new File(targetDir, "surefire-reports");
if (sureFireDir.isDirectory()) {
return sureFireDir.getAbsoluteFile();
}
return targetDir.getAbsoluteFile();
}
URL resource = SolutionCompatibilityFilterTest.class.getResource("SolutionCompatibilityFilterTest.class");
if (resource != null) {
try {
resource = FileLocator.resolve(resource);
if ("file".equalsIgnoreCase(resource.getProtocol())) {
for (File file = new File(resource.toURI()); file != null && file.exists(); file = file
.getParentFile()) {
targetDir = new File(file, "target");
if (targetDir.isDirectory()) {
File sureFireDir = new File(targetDir, "surefire-reports");
if (sureFireDir.isDirectory()) {
return sureFireDir.getAbsoluteFile();
}
return targetDir.getAbsoluteFile();
}
}
}
} catch (Exception e) {
}
}
return new File(java.lang.System.getProperty("user.dir"));
}
private String safeFileName(String text) {
char[] fileName = text.toCharArray();
for (int i = 0; i < fileName.length; i++) {
char c = fileName[i];
if (!((c >= 48 && c <= 57 /* [0-9] */) || (c >= 65 && c <= 90 /* [A-Z] */)
|| (c >= 97 && c <= 122 /* [a-z] */) || c == 45 /* - */|| c == 46 /* . */|| c == 95 /* _ */)) {
fileName[i] = '_';
}
}
return new String(fileName);
}
};
@Rule
public TestRule logRule = new TestRule() {
public Statement apply(final Statement base, final Description description) {
return LoggingSuite.isLogging() ? base : new Statement() {
@Override
public void evaluate() throws Throwable {
try {
log("Starting test " + description.getDisplayName());
base.evaluate();
} finally {
log("Finished test " + description.getDisplayName());
}
}
private void log(String message) {
MarketplaceClientCore.error(message, null);
java.lang.System.out.println(message);
}
};
}
};
@Rule
public TestRule requestInfoRule = new TestRule() {
public Statement apply(final Statement base, final Description description) {
String methodName = description.getMethodName();
if (methodName.contains("SearchResult")) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
try {
base.evaluate();
} catch (AssertionError t) {
failedSearchQuery(t, description);
}
}
};
} else {
return new Statement() {
@Override
public void evaluate() throws Throwable {
try {
base.evaluate();
} catch (AssertionError t) {
failedNodeQuery(t, description);
}
}
};
}
}
protected void failedSearchQuery(AssertionError error, Description description) {
String request = marketplaceService.addMetaParameters(BASE_URL + "/"
+ DefaultMarketplaceService.API_SEARCH_URI_FULL + solution.query());
String queryDetail = "Unexpected result in search for node " + solution.shortName() + "\n " + request;
failedWithDetails(error, queryDetail);
}
protected void failedNodeQuery(AssertionError error, Description description) {
String queryDetail = "Unexpected result in query for node " + solution.shortName() + "\n "
+ marketplaceService.addMetaParameters(solution.url() + "/api/p");
failedWithDetails(error, queryDetail);
}
protected void failedWithDetails(AssertionError error, String queryDetail) throws AssertionError {
String message = error.getMessage() == null ? queryDetail : queryDetail + "\n\n" + error.getMessage();
String testDescription = SolutionCompatibilityFilterTest.this.testDescription;
if (testDescription != null) {
message = testDescription + "\n\n" + message;
}
throw adaptAssertionError(error, message);
}
protected AssertionError adaptAssertionError(AssertionError error, String message) {
if (message == null || message.equals(error.getMessage())) {
return error;
}
AssertionError newError;
if (error.getClass() == AssertionError.class) {
newError = new AssertionError(message);
} else if (error.getClass() == ComparisonFailure.class) {
ComparisonFailure comparisonFailure = (ComparisonFailure) error;
newError = new ComparisonFailure(message, comparisonFailure.getExpected(), comparisonFailure
.getActual());
} else {
newError = new AssertionError(message);
newError.initCause(error);
}
newError.setStackTrace(error.getStackTrace());
return newError;
}
};
@Parameter(0)
public Solution solution;
@Parameter(1)
public EclipseRelease eclipseRelease;
@Parameter(2)
public System system;
@Parameter(3)
public String version;
@Parameter(4)
public String site;
@Parameter(5)
public String[] features;
@Parameter(6)
public boolean compatible;
@Parameter(7)
public String testDescription;
private DefaultMarketplaceService marketplaceService;
@Before
public void setupMarketplaceService() throws Exception {
marketplaceService = new DefaultMarketplaceService(new URL(BASE_URL));
marketplaceService.setRequestMetaParameters(computeRequestMetaParameters(system, eclipseRelease));
}
protected Map<String, String> computeRequestMetaParameters(System system, EclipseRelease eclipseRelease) {
Map<String, String> requestMetaParameters = ServiceLocator.computeDefaultRequestMetaParameters();
system.applyTo(requestMetaParameters);
eclipseRelease.applyTo(requestMetaParameters);
return requestMetaParameters;
}
protected INode queryNode() throws CoreException {
INode node = marketplaceService.getNode(QueryHelper.nodeByUrl(solution.url()), new NullProgressMonitor());
assertNotNull("Node {0} not found", node);
if (solution.id() != null) {
assertEquals("Node {2} returned with wrong id {1}", solution.id(), node.getId(), solution);
}
if (solution.url() != null) {
assertEquals("Node {2} returned with wrong url {1}", solution.url(), node.getUrl(), solution);
}
return node;
}
protected INode searchForNode() throws CoreException {
ISearchResult searchResult = marketplaceService.search(null, null, solution.query(), new NullProgressMonitor());
assertSearchResultSanity(searchResult);
List<? extends INode> nodes = searchResult.getNodes();
INode foundNode = null;
for (INode node : nodes) {
if ((solution.id() != null && solution.id().equals(node.getId()))
|| (solution.url() != null && solution.url().equals(node.getUrl()))) {
foundNode = node;
break;
}
}
return foundNode;
}
protected void assertSearchResultSanity(ISearchResult result) {
assertNotNull("Search result is null", result);
assertNotNull("Result node list is null (internal error)", result.getNodes());
assertNotNull("Result match count is null ('count' attribute missing)", result.getMatchCount());
assertTrue("Total search result count {1} has to be at least the number of returned nodes {2}", result
.getMatchCount() >= result.getNodes().size(), result.getMatchCount(), result.getNodes().size());
Set<String> ids = new HashSet<String>();
for (INode node : result.getNodes()) {
assertNotNull("Search result node {1} without id", node.getId(), node);
assertTrue("Duplicate search result node {1}", ids.add(node.getId()), node);
}
}
@Test
public void testNodeQuery() throws CoreException {
if (compatible) {
if (solution.installable()) {
testCompatibleInstallableNode();
} else {
testCompatibleNonInstallableNode();
}
} else {
testIncompatibleNode();
}
}
public void testCompatibleInstallableNode() throws CoreException {
assumeTrue("Skipping test - this solution and Eclipse/OS are incompatible", compatible);
assumeTrue("Skipping test - this solution is not installable", solution.installable());
INode node = queryNode();
String updateurl = node.getUpdateurl();
assertThat("Node {1} has no update url", updateurl, not(isEmptyOrNullString()), node);
IIus ius = node.getIus();
assertNotNull("Node {1} is missing <ius> element", ius, node);
List<IIu> iuElements = ius.getIuElements();
assertNotNull(iuElements);
assertThat("Node {1} has no IUs", iuElements, not(empty()), node);
if (version != null) {
assertEquals("Node {2} has wrong version", version, node.getVersion(), node);
}
if (site != null) {
assertEquals("Node {2} has wrong update site", site, node.getUpdateurl(), node);
}
if (features != null) {
Set<String> allIUs = new HashSet<String>();
for (IIu iu : iuElements) {
allIUs.add(iu.getId());
}
assertThat("Node {1} is missing some features", allIUs, hasItems(features), node);
assertThat("Node {1} has some unexpected features", allIUs, hasSize(features.length), node);
}
}
public void testCompatibleNonInstallableNode() throws CoreException {
assumeTrue("Skipping test - this solution and Eclipse/OS are incompatible", compatible);
assumeFalse("Skipping test - this solution is installable", solution.installable());
INode node = queryNode();
String updateurl = node.getUpdateurl();
assertNull("Uninstallable node {1} should not have an update url, but has {0}", updateurl, node);
IIus ius = node.getIus();
assertNull("Uninstallable node {1} should not have an <ius> element", ius, node);
}
public void testIncompatibleNode() throws CoreException {
assumeFalse("Skipping test - this solution and Eclipse/OS are compatible", compatible);
INode node = queryNode();
String updateurl = node.getUpdateurl();
assertNull("Incompatible node {1} should not have an update url, but has {0}", updateurl, node);
IIus ius = node.getIus();
assertNull("Incompatible node {1} should not have an <ius> element", ius, node);
}
@Test
public void testSearchResult() throws CoreException {
if (compatible) {
testCompatibleSearchResult();
} else {
testIncompatibleSearchResult();
}
}
public void testCompatibleSearchResult() throws CoreException {
assumeTrue("Skipping test - this solution and Eclipse/OS are incompatible", compatible);
INode foundNode = searchForNode();
assertNotNull("Compatible node {1} not found in search", foundNode, solution);
}
public void testIncompatibleSearchResult() throws CoreException {
assumeFalse("Skipping test - this solution and Eclipse/OS are compatible", compatible);
INode foundNode = searchForNode();
assertNull("Incompatible node {0} found in search", foundNode);
}
}